#pragma once
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <queue>
#include <string>
#include "Cond.hpp"
#include "Mutex.hpp"

using namespace CondModule;
using namespace MutexModule;

const int CAP = 10;

template <class T>
class BlockQueue
{
public:
	BlockQueue(int cap = CAP) : _cap(cap), _csleep(0), _psleep(0) {}

	void Equeue(T data)
	{
		{
			MutexGuard guard(_mutex);

			// 如果队列满了阻塞
			while (IsFull())
			{
				_psleep++;
				_full_cond.Wait(_mutex);
				_psleep--;
			}

			_queue.push(data);

			if (_csleep > 0)
			{
				std::cout << "唤醒一个消费者线程" << std::endl;
				_empty_cond.Signal();
			}
		}
	}

	T Pop()
	{
		T data;
		{
			MutexGuard guard(_mutex);
			while (IsEmpty())
			{
				_csleep++;
				_empty_cond.Wait(_mutex);;
				_csleep--;
			}

			data = _queue.front();
			_queue.pop();

			std::cout << "唤醒一个生产者线程" << std::endl;
			_full_cond.Signal();
		}

		return data;
	}

	~BlockQueue() {}

private:
	std::queue<T> _queue;
	int _cap; // 队列的容量
	Mutex _mutex;
	Cond _full_cond;
	Cond _empty_cond;
	int _csleep; // 休眠的消费者线程数
	int _psleep; // 休眠的生产者线程数

	bool IsFull()
	{
		return _queue.size() == _cap;
	}

	bool IsEmpty()
	{
		return _queue.empty();
	}
};